package com.mingqijia.gassafety.job.job.warnStrategy;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gap.basic.utils.CollectionUtils;
import com.mingqijia.gassafety.db.entity.*;
import com.mingqijia.gassafety.db.entity.vo.SendMessagePhonesVo;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConfiguration;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConnect;
import com.mingqijia.gassafety.db.mapper.*;
import com.mingqijia.gassafety.job.dto.SendMessageDTO;
import com.mingqijia.gassafety.job.request.UpdateDeviceStateRequest;
import com.mingqijia.gassafety.job.service.ConsumerLocationService;
import com.mingqijia.gassafety.job.service.impl.CompanyServiceImpl;
import com.mingqijia.gassafety.job.strategy.impl.LatestLogInnerServiceImpl;
import com.mingqijia.gassafety.shared.constant.BusinessNoticeParam;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.MessagePushTypeEnum;
import com.mingqijia.gassafety.shared.constant.WxTypeEnum;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.mingqijia.gassafety.shared.utils.commonUtils.DateUtils;
import com.mingqijia.gassafety.shared.utils.commonUtils.SnowflakeUtil;
import com.mingqijia.gassafety.shared.utils.message.SendMessageService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;

@Component
@Slf4j
public class DeviceCycleNotificationJob {
    @Autowired
    RedisCacheExt redisUtil;

    @Autowired
    DtuMapper dtuMapper;

    @Autowired
    DeviceStateMapper deviceStateMapper;


    @Autowired
    InfluxDBConfiguration influxDBConfiguration;

    @Autowired
    BusinessNoticeMapper businessNoticeMapper;

    @Autowired
    BusinessNoticeTemplateMapper businessNoticeTemplateMapper;

    @Autowired
    ConsumerMapper consumerMapper;

    @Autowired
    ContactsMapper contactsMapper;

    @Autowired
    SendMessageService sendMessageService;

    @Autowired
    CompanyServiceImpl companyService;

    @Autowired
    InformRecordMapper informRecordMapper;

    @Autowired
    LatestLogInnerServiceImpl latestLogInnerService;

    @Autowired
    ConsumerLocationService consumerLocationService;



    public static final String INFO = "设备离线（通讯不成功）";
    public static final String SEMICOLON = ";";
    public static final String ONE = "1";
    public static final String TWO = "2";
    public static final String THREE = "3";


    /**
     * 0 0 0/10 * * ? 每10小时运行
     */
    @XxlJob("deviceCycleNotification")
    public ReturnT<String> deviceCycleNotification(String param) {
        XxlJobLogger.log("XXLJOB-deviceCycleNotification start...");
        log.info("deviceCycleNotification--start--------");
        String key = Constants.EQUIPMENT_DEVICE_CYCLE_NOTIFICATION;
        try {
            Boolean acquire = redisUtil.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    log.info("deviceCycleNotification--进入执行器--------");
                    if (execute()) {
                        return ReturnT.SUCCESS;
                    } else {
                        return ReturnT.FAIL;
                    }
                } catch (Exception e) {
                    log.info("deviceCycleNotification-error:{}", e);
                } finally {
                    redisUtil.del(key);
                }
            }
        } catch (Exception e) {
            log.info("deviceCycleNotification-error:{}", e);
        }

        log.info("deviceCycleNotification--end--------");
        XxlJobLogger.log("XXLJOB-deviceCycleNotification end...");
        return ReturnT.SUCCESS;
    }

    private boolean execute() {
        // 维护状态
        HashMap<Integer, String> statusMap = new HashMap<>();
        statusMap.put(0,"离线");
        statusMap.put(1,"正常");
        statusMap.put(2,"低报");
        statusMap.put(3,"高报");
        statusMap.put(4,"故障");
        statusMap.put(6,"报警（紫荆wifi）");
        // 获取业务配置规则
        QueryWrapper<BusinessNotice> businessNoticeQueryWrapper = new QueryWrapper<>();
        businessNoticeQueryWrapper.lambda()
                .eq(BusinessNotice::getParamCode, BusinessNoticeParam.DEVICE_OFFLINE_AUTOMATION.getCode())
                .eq(BusinessNotice::getIsDeleted, 0);
        List<BusinessNotice> businessNoticeList = businessNoticeMapper.selectList(businessNoticeQueryWrapper);
        if (CollectionUtils.isEmpty(businessNoticeList)) {
            log.info("设备周期业务没有配置");
            return false;
        }
        for (BusinessNotice businessNotice : businessNoticeList) {
            if( null!=businessNotice.getParamValue() && !"ON".equalsIgnoreCase(businessNotice.getParamValue()) ){
                log.info("企业：{}设备离线之通讯周期设置未开启",businessNotice.getSpId());
                continue;
            }
            // 根据规则先确定范围，再根据范围去查询设备表，拿到设备id，再拿设备id去状态表查找对应的数据，看是否需要更改
            QueryWrapper<DeviceState> queryWrapper = new QueryWrapper<>();
            List<DeviceState> deviceStates = new ArrayList<>();
            int period = 0; // 周期
            // 先获取当前时间，
            Date newDate = new Date();
            //获取数据库连接
            InfluxDBConnect influxDBConnect = influxDBConfiguration.getInfluxDBConnect();
            // 没有进行修改前的设备id集合
            ArrayList<String> preIds = new ArrayList<>();
            // 进行修改后的设备id集合
            ArrayList<String> lastIds = new ArrayList<>();
            // 发送本地消息的集合
            List<UpdateDeviceStateRequest>  updateDeviceStateRequests= new ArrayList<>();
            // 本地消息发送是否发送成功
            boolean loop ;
            switch (businessNotice.getSetRange()) {
                case ONE: {
                    // 范围一：所有设备
//                    queryWrapper.lambda()
//                            .eq(DeviceState::getIsDeleted, 0)
//                            .ne(DeviceState::getDeviceStatus, 0)
//                            .eq(DeviceState::getSpId, businessNotice.getSpId());
//                    deviceStates = deviceStateMapper.selectList(queryWrapper);
                    period = Integer.parseInt(businessNotice.getPeriod());
                    log.info("deviceCycleNotification-execute1-period：{}", period);
                    deviceStates =  deviceStateMapper.queryForDeviceCycleNotice(businessNotice.getSpId(),null, period);
                    log.info("deviceCycleNotification-execute1：{}", JSONObject.toJSONString(deviceStates));
                    //根据当前时间和设备状态表中的时间进行比较，大于等于设置的周期就触发策略
                    if (CollectionUtils.isNotEmpty(deviceStates)) {
                        int finalPeriod = period;
                        deviceStates.forEach(e -> {
                            UpdateDeviceStateRequest updateDeviceStateRequest = new UpdateDeviceStateRequest();
                            updateDeviceStateRequest.setPredeviceState(statusMap.get(e.getDeviceStatus()));
                            updateDeviceStateRequest.setSpId(e.getSpId());
                            long diffInMillis = 0;
                            if (e.getLastReportTime() != null) {
                                diffInMillis = newDate.getTime() - e.getLastReportTime().getTime();
                            }
                            long diffInHours = diffInMillis / (1000 * 60 * 60);
                            if (diffInHours >= finalPeriod) {
                                e.setDeviceStatus(0);
                                e.setDeviceStatusInfo(INFO);
                                e.setLastReportTime(new Date());
                                updateDeviceStateRequest.setImei(e.getDeviceId());
                                updateDeviceStateRequest.setDeviceState("离线");
                                updateDeviceStateRequests.add(updateDeviceStateRequest);
                                log.info("DeviceState: {}", JSONObject.toJSONString(e));
                                if ( businessNotice.getIsNotice() == 0 ){
                                    log.info("execute.DeviceState: {}", JSONObject.toJSONString(e));
                                    deviceStateMapper.updateById(e);

                                    consumerLocationService.updateConsumerLocationDeviceNumByDeviceId(e.getSpId(),e.getDeviceId());
                                }
                                // 存储被修改的设备id
                                lastIds.add(e.getDeviceId());

                            }
                        });
                    }
                    List<Dtu> dtus = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(lastIds)) dtus = dtuMapper.selectBatchIds(lastIds);

                    lastIds.clear(); // 释放资源

                    ArrayList<Integer> ConsumerIds = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(dtus)) {
                        for (Dtu dtu : dtus) {
                            ConsumerIds.add(dtu.getConsumerId());
                            HashMap<String, String> tag = new HashMap<>();
                            HashMap<String, Object> field = new HashMap<>();
                            tag.put("DtuId", dtu.getId());
                            tag.put("Path", dtu.getPath());
                            field.put("Ccid", dtu.getIccid());
                            field.put("ConsumerId", dtu.getConsumerId());
                            field.put("DtuType", Integer.parseInt(dtu.getEquipmentManufacturer()));
                            field.put("Offline", true);
                            field.put("Version",1000);
                            influxDBConnect.insert("PowerLogAsDtu", tag, field);

                        }
                    }
                    // 查询出需要发送消息的客户信息，拿到客户的手机号，下面就是组装微信发送的消息体
                    // 发送消息
                    if (businessNotice.getIsNotice() > 0 && CollectionUtils.isNotEmpty(updateDeviceStateRequests)){
                        latestLogInnerService.LatestLogRequest(updateDeviceStateRequests);
                        updateDeviceStateRequests.clear();
                    }
//                List<SendMessageDTO> sendMessageDTOS = dataAssembly(ConsumerIds, dtus, businessNotice.getSpId());
//                if (CollectionUtils.isNotEmpty(sendMessageDTOS)) {
//                    sendMessageDTOS.forEach(x -> {
//                                // 批量只会有一个回执，分开
//                                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(x.getPhones())) {
//                                    x.getPhones().forEach(phone -> {
//                                        x.setPhone(phone.getTelephone());
//                                        x.setLevel(phone.getLevel());
//                                        List<String> phoneList = new ArrayList<>();
//                                        phoneList.add(phone.getTelephone());
//                                        try {
//                                            pushWx(x, phoneList);
//                                        } catch (Exception e) {
//                                            log.info("deviceCycleNotification-sendMessage-wx-error:{}", e);
//                                        }
//                                    });
//                                }
//                            }
//                    );
//                }
                    break;
                }
                case TWO: {
                    // 范围二：设备类型
                    List<String> equipmentType = new ArrayList<>();
                    List<String> periods = new ArrayList<>();
                    if (businessNotice.getEquipmentType().contains(SEMICOLON)) {
                        equipmentType = Arrays.asList(businessNotice.getEquipmentType().split(SEMICOLON));
                        periods = Arrays.asList(businessNotice.getPeriod().split(SEMICOLON));
                    } else {
                        equipmentType.add(businessNotice.getEquipmentType());
                        periods.add(businessNotice.getPeriod());
                    }
                    QueryWrapper<Dtu> dtuQueryWrapper = new QueryWrapper<>();
                    dtuQueryWrapper.lambda()
                            .eq(Dtu::getIsDeleted, 0)
                            .eq(Dtu::getSpId, businessNotice.getSpId())
                            .in(Dtu::getEquipmentType, equipmentType);
                    List<Dtu> dtus = dtuMapper.selectList(dtuQueryWrapper);
                    // 还需要对设备的数据进行处理，不然再进行设备状态检查的时候，无法根据规则来走
                    Map<String, String> dutMap = new HashMap<>();
                    if (CollectionUtils.isNotEmpty(dtus)) {
                        // 拿到对应范围下的所有设备id
                        for (Dtu dtu : dtus) {
                            preIds.add(dtu.getId());
                            dutMap.put(dtu.getId(), dtu.getEquipmentType());
                        }
                    }
                    // 根据拿到的ids去查询对应的设备状态
//                    queryWrapper.lambda()
//                            .eq(DeviceState::getIsDeleted, 0)
//                            .ne(DeviceState::getDeviceStatus, 0)
//                            .eq(DeviceState::getSpId, businessNotice.getSpId())
//                            .in(DeviceState::getDeviceId, preIds);
//                    deviceStates = deviceStateMapper.selectList(queryWrapper);
                    deviceStates =  deviceStateMapper.queryForDeviceCycleNotice(businessNotice.getSpId(),preIds, null);
                    log.info("deviceCycleNotification-execute2：{}", JSONObject.toJSONString(deviceStates));
                    // 由于这里的设备类型和周期是一一对应的，所有需要使用一个map来进行存储,同时这个两个集合的长度也是一样的，所以只需要循环一个集合就行
                    Map<String, String> Map = new HashMap<>();
                    for (int i = 0; i < equipmentType.size(); i++) {
                        Map.put(equipmentType.get(i), periods.get(i));
                    }
                    //根据当前时间和设备状态表中的时间进行比较，大于等于设置的周期就触发策略

                    if (CollectionUtils.isNotEmpty(deviceStates)) {
                        deviceStates.forEach(e -> {
                            UpdateDeviceStateRequest updateDeviceStateRequest = new UpdateDeviceStateRequest();
                            updateDeviceStateRequest.setPredeviceState(statusMap.get(e.getDeviceStatus()));
                            updateDeviceStateRequest.setSpId(e.getSpId());
                            long diffInMillis = 0;
                            if (e.getLastReportTime() != null) {
                                diffInMillis = newDate.getTime() - e.getLastReportTime().getTime();
                            }
                            long diffInHours = diffInMillis / (1000 * 60 * 60);
                            // 使用两个map，根据规则拿到对应类型的周期
                            String typePeriod = Map.get(dutMap.get(e.getDeviceId()));
                            if (diffInHours >= Integer.parseInt(typePeriod)) {
                                e.setDeviceStatus(0);
                                e.setDeviceStatusInfo(INFO);
                                e.setLastReportTime(new Date());
                                updateDeviceStateRequest.setImei(e.getDeviceId());
                                updateDeviceStateRequest.setDeviceState("离线");
                                updateDeviceStateRequests.add(updateDeviceStateRequest);
                                log.info("DeviceState: {}", JSONObject.toJSONString(e));
                                if (businessNotice.getIsNotice() == 0){
                                    deviceStateMapper.updateById(e);

                                    consumerLocationService.updateConsumerLocationDeviceNumByDeviceId(e.getSpId(),e.getDeviceId());
                                }
                                lastIds.add(e.getDeviceId());
                            }
                        });
                    }

                    List<Dtu> dtuList = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(lastIds)) dtuList = dtuMapper.selectBatchIds(lastIds);

                    ArrayList<Integer> ConsumerIds = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(dtuList)) {
                        for (Dtu dtu : dtuList) {
                            ConsumerIds.add(dtu.getConsumerId());
                            HashMap<String, String> tag = new HashMap<>();
                            HashMap<String, Object> field = new HashMap<>();
                            tag.put("DtuId", dtu.getId());
                            tag.put("Path", dtu.getPath());
                            field.put("Ccid", dtu.getIccid());
                            field.put("ConsumerId", dtu.getConsumerId());
                            field.put("DtuType", Integer.parseInt(dtu.getEquipmentManufacturer()));
                            field.put("Offline", true);
                            field.put("Version",1000);
                            influxDBConnect.insert("PowerLogAsDtu", tag, field);
                        }
                    }
                    // 查询出需要发送消息的客户信息，拿到客户的手机号，下面就是组装微信发送的消息体
                    // 发送消息
                    if (businessNotice.getIsNotice() > 0 && CollectionUtils.isNotEmpty(updateDeviceStateRequests)){
                        latestLogInnerService.LatestLogRequest(updateDeviceStateRequests);
                        updateDeviceStateRequests.clear();
                    }
//                List<SendMessageDTO> sendMessageDTOS = dataAssembly(ConsumerIds, dtuList, businessNotice.getSpId());
//                if (CollectionUtils.isNotEmpty(sendMessageDTOS)) {
//                    sendMessageDTOS.forEach(x -> {
//                                // 批量只会有一个回执，分开
//                                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(x.getPhones())) {
//                                    x.getPhones().forEach(phone -> {
//                                        x.setPhone(phone.getTelephone());
//                                        x.setLevel(phone.getLevel());
//                                        List<String> phoneList = new ArrayList<>();
//                                        phoneList.add(phone.getTelephone());
//                                        try {
//                                            pushWx(x, phoneList);
//                                        } catch (Exception e) {
//                                            log.info("deviceCycleNotification-sendMessage-wx-error:{}", e);
//                                        }
//                                    });
//                                }
//                            }
//                    );
//                }
                    break;
                }
                case THREE: {
                    // 范围三：设备厂商+设备型号
                    List<String> equipmentManufacturer = new ArrayList<>();
                    List<String> periods = new ArrayList<>();
                    List<String> equipmentModel = new ArrayList<>();
                    if (businessNotice.getEquipmentModel().contains(SEMICOLON)) {
                        equipmentManufacturer = Arrays.asList(businessNotice.getEquipmentManufacturer().split(SEMICOLON));
                        equipmentModel = Arrays.asList(businessNotice.getEquipmentModel().split(SEMICOLON));
                        periods = Arrays.asList(businessNotice.getPeriod().split(SEMICOLON));
                    } else {
                        equipmentManufacturer.add(businessNotice.getEquipmentManufacturer());
                        equipmentModel.add(businessNotice.getEquipmentModel());
                        periods.add(businessNotice.getPeriod());
                    }
                    // 由与厂商可能存在一对多的场景，这里只进行型号和周期的比对
                    QueryWrapper<Dtu> dtuQueryWrapper = new QueryWrapper<>();
                    dtuQueryWrapper.lambda()
                            .eq(Dtu::getIsDeleted, 0)
                            .eq(Dtu::getSpId, businessNotice.getSpId())
                            .in(Dtu::getEquipmentManufacturer, equipmentManufacturer)
                            .in(Dtu::getEquipmentModel, equipmentModel);
                    List<Dtu> dtus = dtuMapper.selectList(dtuQueryWrapper);
                    // 还需要对设备的数据进行处理，不然再进行设备状态检查的时候，无法根据规则来走
                    Map<String, String> dutMap = new HashMap<>();
                    if (CollectionUtils.isNotEmpty(dtus)) {
                        // 拿到对应范围下的所有设备id
                        for (Dtu dtu : dtus) {
                            preIds.add(dtu.getId());
                            dutMap.put(dtu.getId(), dtu.getEquipmentModel());
                        }
                    }
                    // 根据拿到的ids去查询对应的设备状态
//                    queryWrapper.lambda()
//                            .eq(DeviceState::getIsDeleted, 0)
//                            .ne(DeviceState::getDeviceStatus, 0)
//                            .eq(DeviceState::getSpId, businessNotice.getSpId())
//                            .in(DeviceState::getDeviceId, preIds);
//                    deviceStates = deviceStateMapper.selectList(queryWrapper);
                    deviceStates =  deviceStateMapper.queryForDeviceCycleNotice(businessNotice.getSpId(),preIds, null);
                    log.info("deviceCycleNotification-execute3：{}", JSONObject.toJSONString(deviceStates));
                    // 由于这里的设备型号和周期是一一对应的，所有需要使用一个map来进行存储,同时这个两个集合的长度也是一样的，所以只需要循环一个集合就行
                    Map<String, String> Map = new HashMap<>();
                    for (int i = 0; i < equipmentModel.size(); i++) {
                        Map.put(equipmentModel.get(i), periods.get(i));
                    }
                    //根据当前时间和设备状态表中的时间进行比较，大于等于设置的周期就触发策略
                    if (CollectionUtils.isNotEmpty(deviceStates)) {
                        deviceStates.forEach(e -> {
                            long diffInMillis = 0;
                            if (e.getLastReportTime() != null) {
                                diffInMillis = newDate.getTime() - e.getLastReportTime().getTime();
                            }
                            long diffInHours = diffInMillis / (1000 * 60 * 60);
                            // 使用两个map，根据规则拿到对应类型的周期
                            String typePeriod = Map.get(dutMap.get(e.getDeviceId()));
                            if (diffInHours >= Integer.parseInt(typePeriod)) {
                                UpdateDeviceStateRequest updateDeviceStateRequest = new UpdateDeviceStateRequest();
                                updateDeviceStateRequest.setPredeviceState(statusMap.get(e.getDeviceStatus()));
                                updateDeviceStateRequest.setSpId(e.getSpId());
                                e.setDeviceStatus(0);
                                e.setDeviceStatusInfo(INFO);
                                e.setLastReportTime(new Date());
                                updateDeviceStateRequest.setImei(e.getDeviceId());
                                updateDeviceStateRequest.setDeviceState("离线");
                                updateDeviceStateRequests.add(updateDeviceStateRequest);
                                log.info("DeviceState: {}", JSONObject.toJSONString(e));
                                if (businessNotice.getIsNotice() == 0){
                                    deviceStateMapper.updateById(e);

                                    consumerLocationService.updateConsumerLocationDeviceNumByDeviceId(e.getSpId(),e.getDeviceId());
                                }
                                lastIds.add(e.getDeviceId());
                            }
                        });
                    }

                    List<Dtu> dtuList = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(lastIds)) dtuList = dtuMapper.selectBatchIds(lastIds);

                    ArrayList<Integer> ConsumerIds = new ArrayList<>();
                    if (CollectionUtils.isNotEmpty(dtuList)) {
                        for (Dtu dtu : dtuList) {
                            ConsumerIds.add(dtu.getConsumerId());
                            HashMap<String, String> tag = new HashMap<>();
                            HashMap<String, Object> field = new HashMap<>();
                            tag.put("DtuId", dtu.getId());
                            tag.put("Path", dtu.getPath());
                            field.put("Ccid", dtu.getIccid());
                            field.put("ConsumerId", dtu.getConsumerId());
                            field.put("DtuType", Integer.parseInt(dtu.getEquipmentManufacturer()));
                            field.put("Offline", true);
                            field.put("Version",1000);
                            influxDBConnect.insert("PowerLogAsDtu", tag, field);
                        }
                    }
                    // 查询出需要发送消息的客户信息，拿到客户的手机号，下面就是组装微信发送的消息体
                    // 发送消息
                    if (businessNotice.getIsNotice() > 0 && CollectionUtils.isNotEmpty(updateDeviceStateRequests)){
                        latestLogInnerService.LatestLogRequest(updateDeviceStateRequests);
                        updateDeviceStateRequests.clear();
                    }
//                List<SendMessageDTO> sendMessageDTOS = dataAssembly(ConsumerIds, dtuList, businessNotice.getSpId());
//                if (CollectionUtils.isNotEmpty(sendMessageDTOS)) {
//                    sendMessageDTOS.forEach(x -> {
//                                // 批量只会有一个回执，分开
//                                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(x.getPhones())) {
//                                    x.getPhones().forEach(phone -> {
//                                        x.setPhone(phone.getTelephone());
//                                        x.setLevel(phone.getLevel());
//                                        List<String> phoneList = new ArrayList<>();
//                                        phoneList.add(phone.getTelephone());
//                                        try {
//                                            pushWx(x, phoneList);
//                                        } catch (Exception e) {
//                                            log.info("deviceCycleNotification-sendMessage-wx-error:{}", e);
//                                        }
//                                    });
//                                }
//                            }
//                    );
//                }

                    break;
                }
                default:
                    log.info("设备周期业务配置范围不正确");
                    return false;
            }
            updateDeviceStateRequests.clear();
            // 下面return的话for循环只会执行一次
            // return true;
        }
        return true;
    }

    //进行数据组装

    /**
     * @param ConsumerIds 需要进行消息发送的所有客户id
     * @param dtuList     需要进行消息发送的所有设备
     * @return
     */
    private List<SendMessageDTO> dataAssembly(List<Integer> ConsumerIds, List<Dtu> dtuList, String spId) {
        ArrayList<SendMessageDTO> data = new ArrayList<>();
        List<SendMessagePhonesVo> phones = new ArrayList<>();
        List<Contacts> contacts = contactsMapper.highestListByIds(ConsumerIds, spId);
        log.info("联系人数据：{}", contacts);
        HashMap<Integer, Contacts> constantsHashMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(contacts)) {
            for (Contacts contact : contacts) {
                constantsHashMap.put(contact.getConsumerId(), contact);
            }
        }
        // 由于一个客户可能对应多台设备，所以需要根据设备来进行数组组装
        log.info("设备数据：{}", dtuList);
        for (Dtu dtu : dtuList) {
            Long snowflakeId = SnowflakeUtil.getSnowflakeId();
            String orgCode = companyService.getOrgCode(spId, String.valueOf(dtu.getConsumerId()));
            QueryWrapper<Consumer> consumerQuery = new QueryWrapper<>();
            consumerQuery.lambda().eq(Consumer::getIsDeleted, 0)
                    .eq(Consumer::getSpId, dtu.getSpId())
                    .eq(Consumer::getId, dtu.getConsumerId());
            Consumer consumer = consumerMapper.selectOne(consumerQuery);
            log.info("客户数据：{}", consumer);
            SendMessageDTO dto = new SendMessageDTO();
            dto.setEndDate(DateUtils.dateFormat(new Date()));
            dto.setConsumerId(dtu.getConsumerId());
            dto.setSpId(dtu.getSpId());
            dto.setImei(dtu.getIMEI());
            dto.setPushType(MessagePushTypeEnum.WX.getCode());

            SendMessagePhonesVo phonesVo = new SendMessagePhonesVo();
            if (constantsHashMap.get(dtu.getConsumerId()) != null){
                phonesVo.setTelephone(constantsHashMap.get(dtu.getConsumerId()).getTelephone());
                phonesVo.setLevel(constantsHashMap.get(dtu.getConsumerId()).getLevel() != null ? String.valueOf(constantsHashMap.get(dtu.getConsumerId()).getLevel()): "0");
                phones.add(phonesVo);
            }
            dto.setPhones(phones);
            dto.setOrgCode(orgCode);
            dto.setSnowflakeId(snowflakeId);
            Map<String, Object> param = new HashMap<>();
            dto.setParam(param);
            param.put("Time", dto.getEndDate());
            dto.setPosition(dtu.getInstallationPosition());
            param.put("position", dtu.getInstallationPosition());
            if (consumer != null) {
                dto.setAddress(consumer.getAddress());
                dto.setCustName(consumer.getCustName());
                dto.setSubsCode(consumer.getSubsCode());
                param.put("address", dtu.getInstallationPosition());
                param.put("subsName", consumer.getCustName());
                param.put("subsCode", consumer.getSubsCode());
            }
            param.put("IMEI", dto.getImei());
            dto.setContent(getWxTemplate(dto));
            data.add(dto);
        }
        return data;
    }

    public String getWxTemplate(SendMessageDTO dto) {
        return Constants.WARNING_WX_DEVICE_OFFLINE
                .replace("#Time#", dto.getEndDate() == null ? "" : dto.getEndDate())
                .replace("#IMEI#", dto.getImei() == null ? "" : dto.getImei())
                .replace("#subsName#", dto.getCustName() == null ? "" : dto.getCustName())
                .replace("#subsCode#", dto.getSubsCode() == null ? "" : dto.getSubsCode())
                .replace("#address#", dto.getAddress() == null ? "" : dto.getAddress());

    }

    public void pushWx(SendMessageDTO dto, List<String> phones) {
        log.info("deviceCycleNotification-sendWx:imei:{},subsCode:{},phone:{}", dto.getImei(), dto.getSubsCode(), dto.getPhone());
        Map<String, Object> sms = sendMessageService
                .sendSms(sendMessageService
                                .getRequestParam(null
                                        , WxTypeEnum.PUSH_3.getName(), dto.getOrgCode()
                                        , dto.getParam(), MessagePushTypeEnum.WX.getType(), new ArrayList<>(), dto.getSubsCode(), phones, 0)
                        , "");
        if (sms.get("result").equals(true)) {
            //发送成功
            String errorMsg = "发送成功";
            if (sms.get("data") != null) {
                HashMap<String, Object> req = new HashMap<>();
                req.put("ids", sms.get("data"));
                req.put("orgCode", dto.getOrgCode());
                Map<String, Object> resMap = sendMessageService.subTaskDetail(req, "");
                //延迟获取数据
                errorMsg = resMap != null ? (String) resMap.get("errorMsg") : "";
            }
            saveWarningRecord(dto, new Date(), !StringUtils.isEmpty(errorMsg) ? errorMsg + "" : "发送成功",
                    JSONObject.toJSONString(sms.get("data")), !StringUtils.isEmpty(errorMsg) ? 1 : 0, 0);
            log.info("deviceCycleNotification-sendWx-发送日志:{}回执消息:{}", dto.getPhone(), JSONObject.toJSONString(sms));
        } else {
            String errMsg = (String)sms.get("errMsg");
            saveWarningRecord(dto, new Date(), !StringUtils.isEmpty(errMsg) ? errMsg + "" : "发送成功",
                    JSONObject.toJSONString(sms.get("data")), !StringUtils.isEmpty(errMsg) ? 1 : 0, 0);
        }
    }

    /**
     * 保存设备离线通知记录
     *
     * @param dto          设备离线基础数据
     * @param date         时间
     * @param errorMessage 错误信息
     * @param receiptCode  回执编码
     * @param sendResult   发送结果
     * @param status       执行状态
     */
    public void saveWarningRecord(SendMessageDTO dto, Date date, String errorMessage, String receiptCode, Integer sendResult, Integer status) {
        InformRecord warningRecord = new InformRecord();
        warningRecord.setConsumerId(String.valueOf(dto.getConsumerId()));
        warningRecord.setStartTime(date);
        warningRecord.setEndTime(date);
        warningRecord.setTriggerRuleId(dto.getStrategyId());
        warningRecord.setIMEI(dto.getImei());
        warningRecord.setTaskIdentificationCode(String.valueOf(dto.getSnowflakeId()));
        warningRecord.setSendType(dto.getPushType());
        warningRecord.setObjLevel(dto.getLevel());
        warningRecord.setSpId(dto.getSpId());
        warningRecord.setSendResult(sendResult);
        warningRecord.setStatus(status);
        warningRecord.setContent(dto.getContent());
        warningRecord.setReceiptCode(receiptCode);
        warningRecord.setPushPhone(dto.getPhone());
        warningRecord.setRemark(!StringUtils.isEmpty(errorMessage) ? errorMessage : "发送成功");
        log.info("saveWarningRecord:{}", JSONObject.toJSONString(warningRecord));
        informRecordMapper.insert(warningRecord);
    }
}
